module datapath(
input clk, //clock
output done //done bit
);

reg donereg=0;
assign done=donereg;

//define control signals//
wire regdst,
jump,
branch,
memread,
memtoreg,
memwrite,
alusrc,
regwrite;
wire [2:0] op; //3-bit op from ALU Control


// !!important!! branch & zero gate//
wire zero; //bit for zero/nonzero(from ALU)
wire branching; //THE LAST control signal for branch
and(branching, branch, zero);
// !!important!! branch & zero gate//

//define PC//
reg [31:0] PC;
initial begin
PC=0;
end

//define PC//


//connect Instruction memory..//
wire [31:0] current_insn; //wire for current insn
insn_memory im(PC, current_insn);
//connect Instruction memory..//


//define PC control//

//PC = PC+4//
wire [31:0] next_insn;
datapath_addr_add pc4(PC, 32'h0000_0004, next_insn); //pc = pc+4
//PC = PC+4//

//PC branch : Unconditional//
//in this processor, 'J 10' goes to 'line 10'.
//not goes to '+10'.
//i know there's a limitation on this design. it cannot go farther than 2^26.
wire [31:0] jump_insn;
assign jump_insn = {6'b00_0000, current_insn[25:0]};
//PC branch : Unconditional//

//PC branch : Conditional//
//sign extend//
wire [31:0] extended_imm;
assign extended_imm = {current_insn[15],current_insn[15],current_insn[15],current_insn[15],
current_insn[15],current_insn[15],current_insn[15],current_insn[15],
current_insn[15],current_insn[15],current_insn[15],current_insn[15],
current_insn[15],current_insn[15],current_insn[15],current_insn[15],
current_insn[15:0]}; //extended
wire [31:0] ext_shf_imm;
assign ext_shf_imm = {extended_imm[29:0], extended_imm[31], extended_imm[31]}; //left-shifted(2)
wire [31:0] branch_insn;
datapath_addr_add pcimm(next_insn, ext_shf_imm, branch_insn);
//PC branch : Conditional//

//now, we have..
//next_insn//
//jump_insn//
//branch_insn//

//selecting PC(Round 1) : PC+4 vs Branched. by branching//
wire [31:0] b_or_n; //branched vs +4
//it was too long.. i made module
datapath_addr_mux adm1(next_insn, branch_insn, branching, b_or_n);

//selecting PC(Round 2) : b_or_n vs jump_insn by jump//
wire [31:0] next;
datapath_addr_mux adm2(b_or_n, jump_insn, jump, next);

always @(negedge clk && !(done)) begin
PC=next;
if(PC==32'h30)
donereg=1;
end

//define PC control//



//put in control unit..//
ctrl_unit cu(current_insn[31:26], current_insn[5:0], 
regdst,
alusrc,
memtoreg,
regwrite,
memread,
memwrite,
branch, 
jump, 
op);


//put into regfile..//
wire [4:0] write; //wire for register

//selecting writing register's no. : insn[20:16] vs insn[15:11]. by RegDst//
datapath_one_mux write4(current_insn[20], current_insn[15], regdst, write[4]);
datapath_one_mux write3(current_insn[19], current_insn[14], regdst, write[3]);
datapath_one_mux write2(current_insn[18], current_insn[13], regdst, write[2]);
datapath_one_mux write1(current_insn[17], current_insn[12], regdst, write[1]);
datapath_one_mux write0(current_insn[16], current_insn[11], regdst, write[0]);
//selecting writing register's no. : insn[20:16] vs insn[15:11]. by RegDst//

wire [7:0] write_data; //wire for writing data

wire [7:0] rd1, rd2; //2 8-bit data which has been read

regfile rf(current_insn[25:21], current_insn[20:16], write, write_data, regwrite, clk, rd1, rd2);
//put into regfile..//


//put into ALU..//

wire [7:0] opdata; //8-bit data for ALU

//select opdata : rd2 vs insn[15:0]. by AluSrc//
datapath_one_mux op7(rd2[7], current_insn[7], alusrc, opdata[7]);
datapath_one_mux op6(rd2[6], current_insn[6], alusrc, opdata[6]);
datapath_one_mux op5(rd2[5], current_insn[5], alusrc, opdata[5]);
datapath_one_mux op4(rd2[4], current_insn[4], alusrc, opdata[4]);
datapath_one_mux op3(rd2[3], current_insn[3], alusrc, opdata[3]);
datapath_one_mux op2(rd2[2], current_insn[2], alusrc, opdata[2]);
datapath_one_mux op1(rd2[1], current_insn[1], alusrc, opdata[1]);
datapath_one_mux op0(rd2[0], current_insn[0], alusrc, opdata[0]);
//select opdata : rd2 vs insn[15:0]. by AluSrc//

//alu cannot do longer than 8-bit, so we took 8-bit from imm..
wire [7:0] result; //8-bit result
alu core_alu(rd1, opdata, op, result, zero);
//put into ALU..//


//put into data memory..//
wire [7:0] read_data; //data which has been loaded
data_memory dm(result, rd2, clk, memwrite, memread, read_data);
//put into data memory..//


//select write_data : read_data vs result. by memtoreg//
datapath_one_mux write_data7(result[7], read_data[7], memtoreg, write_data[7]);
datapath_one_mux write_data6(result[6], read_data[6], memtoreg, write_data[6]);
datapath_one_mux write_data5(result[5], read_data[5], memtoreg, write_data[5]);
datapath_one_mux write_data4(result[4], read_data[4], memtoreg, write_data[4]);
datapath_one_mux write_data3(result[3], read_data[3], memtoreg, write_data[3]);
datapath_one_mux write_data2(result[2], read_data[2], memtoreg, write_data[2]);
datapath_one_mux write_data1(result[1], read_data[1], memtoreg, write_data[1]);
datapath_one_mux write_data0(result[0], read_data[0], memtoreg, write_data[0]);
//select write_data : read_data vs result. by memtoreg//

endmodule




module datapath_one_mux( //mux for datapath(control signal)
input a, b, //0->a, 1->b.
input signal, //control signal : 1bit
output r //selected value
);
wire x,y;
and(x, a, ~signal);
and(y, b, signal);
or(r, x, y);
endmodule

module datapath_addr_mux( //mux for 32-bit address value
input [31:0] a, b,
input signal,
output [31:0] r
);
datapath_one_mux m31(a[31], b[31], signal, r[31]);
datapath_one_mux m30(a[30], b[30], signal, r[30]);
datapath_one_mux m29(a[29], b[29], signal, r[29]);
datapath_one_mux m28(a[28], b[28], signal, r[28]);
datapath_one_mux m27(a[27], b[27], signal, r[27]);
datapath_one_mux m26(a[26], b[26], signal, r[26]);
datapath_one_mux m25(a[25], b[25], signal, r[25]);
datapath_one_mux m24(a[24], b[24], signal, r[24]);
datapath_one_mux m23(a[23], b[23], signal, r[23]);
datapath_one_mux m22(a[22], b[22], signal, r[22]);
datapath_one_mux m21(a[21], b[21], signal, r[21]);
datapath_one_mux m20(a[20], b[20], signal, r[20]);
datapath_one_mux m19(a[19], b[19], signal, r[19]);
datapath_one_mux m18(a[18], b[18], signal, r[18]);
datapath_one_mux m17(a[17], b[17], signal, r[17]);
datapath_one_mux m16(a[16], b[16], signal, r[16]);
datapath_one_mux m15(a[15], b[15], signal, r[15]);
datapath_one_mux m14(a[14], b[14], signal, r[14]);
datapath_one_mux m13(a[13], b[13], signal, r[13]);
datapath_one_mux m12(a[12], b[12], signal, r[12]);
datapath_one_mux m11(a[11], b[11], signal, r[11]);
datapath_one_mux m10(a[10], b[10], signal, r[10]);
datapath_one_mux m9(a[9], b[9], signal, r[9]);
datapath_one_mux m8(a[8], b[8], signal, r[8]);
datapath_one_mux m7(a[7], b[7], signal, r[7]);
datapath_one_mux m6(a[6], b[6], signal, r[6]);
datapath_one_mux m5(a[5], b[5], signal, r[5]);
datapath_one_mux m4(a[4], b[4], signal, r[4]);
datapath_one_mux m3(a[3], b[3], signal, r[3]);
datapath_one_mux m2(a[2], b[2], signal, r[2]);
datapath_one_mux m1(a[1], b[1], signal, r[1]);
datapath_one_mux m0(a[0], b[0], signal, r[0]);

endmodule

module datapath_addr_add( //adder for 32-bit address values
input [31:0] a, b, //32bit a,b
output [31:0] r //32bit result
);

wire [31:0] c; //wire for carry
assign c[0]=0;
wire [95:0] m; //wire between gates

xor(r[0], a[0], b[0], c[0]);
and(m[0], a[0], b[0]);
or(m[1], a[0], b[0]);
and(m[2], m[1], c[0]);
or(c[1], m[2], m[0]);

xor(r[1], a[1], b[1], c[1]);
and(m[3], a[1], b[1]);
or(m[4], a[1], b[1]);
and(m[5], m[4], c[1]);
or(c[2], m[3], m[5]);

xor(r[2], a[2], b[2], c[2]);
and(m[6], a[2], b[2]);
or(m[7], a[2], b[2]);
and(m[8], m[7], c[2]);
or(c[3], m[6], m[8]);

xor(r[3], a[3], b[3], c[3]);
and(m[9], a[3], b[3]);
or(m[10], a[3], b[3]);
and(m[11], m[10], c[3]);
or(c[4], m[9], m[11]);

xor(r[4], a[4], b[4], c[4]);
and(m[12], a[4], b[4]);
or(m[13], a[4], b[4]);
and(m[14], m[13], c[4]);
or(c[5], m[12], m[14]);

xor(r[5], a[5], b[5], c[5]);
and(m[15], a[5], b[5]);
or(m[16], a[5], b[5]);
and(m[17], m[16], c[5]);
or(c[6], m[15], m[17]);

xor(r[6], a[6], b[6], c[6]);
and(m[18], a[6], b[6]);
or(m[19], a[6], b[6]);
and(m[20], m[19], c[6]);
or(c[7], m[18], m[20]);

xor(r[7], a[7], b[7], c[7]);
and(m[21], a[7], b[7]);
or(m[22], a[7], b[7]);
and(m[23], m[22], c[7]);
or(c[8], m[21], m[23]);

xor(r[8], a[8], b[8], c[8]);
and(m[24], a[8], b[8]);
or(m[25], a[8], b[8]);
and(m[26], m[25], c[8]);
or(c[9], m[24], m[26]);

xor(r[9], a[9], b[9], c[9]);
and(m[27], a[9], b[9]);
or(m[28], a[9], b[9]);
and(m[29], m[28], c[9]);
or(c[10], m[27], m[29]);

xor(r[10], a[10], b[10], c[10]);
and(m[30], a[10], b[10]);
or(m[31], a[10], b[10]);
and(m[32], m[31], c[10]);
or(c[11], m[30], m[32]);

xor(r[11], a[11], b[11], c[11]);
and(m[33], a[11], b[11]);
or(m[34], a[11], b[11]);
and(m[35], m[34], c[11]);
or(c[12], m[33], m[35]);

xor(r[12], a[12], b[12], c[12]);
and(m[36], a[12], b[12]);
or(m[37], a[12], b[12]);
and(m[38], m[37], c[12]);
or(c[13], m[36], m[38]);

xor(r[13], a[13], b[13], c[13]);
and(m[39], a[13], b[13]);
or(m[40], a[13], b[13]);
and(m[41], m[40], c[13]);
or(c[14], m[39], m[41]);

xor(r[14], a[14], b[14], c[14]);
and(m[42], a[14], b[14]);
or(m[43], a[14], b[14]);
and(m[44], m[43], c[14]);
or(c[15], m[42], m[44]);

xor(r[15], a[15], b[15], c[15]);
and(m[45], a[15], b[15]);
or(m[46], a[15], b[15]);
and(m[47], m[46], c[15]);
or(c[16], m[45], m[47]);


xor(r[16], a[16], b[16], c[16]);
and(m[48], a[16], b[16]);
or(m[49], a[16], b[16]);
and(m[50], m[49], c[16]);
or(c[17], m[48], m[50]);

xor(r[17], a[17], b[17], c[17]);
and(m[51], a[17], b[17]);
or(m[52], a[17], b[17]);
and(m[53], m[52], c[17]);
or(c[18], m[51], m[53]);

xor(r[18], a[18], b[18], c[18]);
and(m[54], a[18], b[18]);
or(m[55], a[18], b[18]);
and(m[56], m[55], c[18]);
or(c[19], m[54], m[56]);

xor(r[19], a[19], b[19], c[19]);
and(m[57], a[19], b[19]);
or(m[58], a[19], b[19]);
and(m[59], m[58], c[19]);
or(c[20], m[57], m[59]);

xor(r[20], a[20], b[20], c[20]);
and(m[60], a[20], b[20]);
or(m[61], a[20], b[20]);
and(m[62], m[61], c[20]);
or(c[21], m[60], m[62]);

xor(r[21], a[21], b[21], c[21]);
and(m[63], a[21], b[21]);
or(m[64], a[21], b[21]);
and(m[65], m[64], c[21]);
or(c[22], m[63], m[65]);

xor(r[22], a[22], b[22], c[22]);
and(m[66], a[22], b[22]);
or(m[67], a[22], b[22]);
and(m[68], m[67], c[22]);
or(c[23], m[68], m[66]);

xor(r[23], a[23], b[7], c[7]);
and(m[69], a[23], b[7]);
or(m[70], a[23], b[7]);
and(m[71], m[22], c[7]);
or(c[24], m[21], m[23]);


xor(r[24], a[24], b[24], c[24]);
and(m[72], a[24], b[24]);
or(m[73], a[24], b[24]);
and(m[74], m[73], c[24]);
or(c[25], m[72], m[74]);

xor(r[25], a[25], b[25], c[25]);
and(m[75], a[25], b[25]);
or(m[76], a[25], b[25]);
and(m[77], m[76], c[25]);
or(c[26], m[75], m[77]);

xor(r[26], a[26], b[26], c[26]);
and(m[78], a[26], b[26]);
or(m[79], a[26], b[26]);
and(m[80], m[79], c[26]);
or(c[27], m[78], m[80]);

xor(r[27], a[27], b[27], c[27]);
and(m[81], a[27], b[27]);
or(m[82], a[27], b[27]);
and(m[83], m[82], c[27]);
or(c[28], m[81], m[83]);

xor(r[28], a[28], b[28], c[28]);
and(m[84], a[28], b[28]);
or(m[85], a[28], b[28]);
and(m[86], m[85], c[28]);
or(c[29], m[84], m[86]);

xor(r[29], a[29], b[29], c[29]);
and(m[87], a[29], b[29]);
or(m[88], a[29], b[29]);
and(m[89], m[88], c[29]);
or(c[30], m[87], m[89]);

xor(r[30], a[30], b[30], c[30]);
and(m[90], a[30], b[30]);
or(m[91], a[30], b[30]);
and(m[92], m[91], c[30]);
or(c[31], m[90], m[92]);

xor(r[31], a[31], b[31], c[31]);

//discard last carry//

endmodule